package com.michaelbulava.TFS.ui.controls.connect;

import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.ui.helpers.UIHelpers;
import com.microsoft.tfs.core.util.ServerURIUtils;
import com.microsoft.tfs.core.util.URIUtils;
import com.microsoft.tfs.util.LocaleInvariantStringHelpers;
import com.microsoft.tfs.util.valid.Validator;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.MaskFormatter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URI;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.regex.Pattern;

/**
 * Created by mbulava on 6/15/2015.
 */
public class AddServerControl extends JPanel {
    private static final String[] HOSTED_SERVICE_DOMAIN_SUFFIXES = { ".tfspreview.com", ".visualstudio.com" };
    private static final String HOSTED_SERVICE_DEFAULT_SCHEME = "https";
    private static final String DEFAULT_PATH = "tfs";
    private static final String DEFAULT_PORT_HTTP = "8080";
    private static final String DEFAULT_PORT_HTTPS = "443";
    private static final String WELL_KNOWN_PORT_HTTP = "80";
    private static final String WELL_KNOWN_PORT_HTTPS = "443";

    private JTextField serverText;

    private JTextField pathText;
    private JFormattedTextField portText;
    private JRadioButton HTTPRadioButton;
    private JRadioButton HTTPSRadioButton;
    private JTextField previewText;
    private JPanel connectionDetails;
    private final TextControlURLOrHostnameValidator validator;
    private URI serverURI;

    ButtonGroup protocolGroup;

    private DocumentListener textModifyListener = new DocumentListener() {
        @Override
        public void insertUpdate(DocumentEvent e) {
            refresh();
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            refresh();
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            refresh();
        }
    };

    private ActionListener ProtocolButtonListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            protocolButtonSelected();
        }
    };

    public AddServerControl(){
        super();
        setupUI();

        this.validator = new TextControlURLOrHostnameValidator(this.serverText,
                Messages.getString("AddServerControl.NameOrUrlFieldName"), true);

        this.serverText.getDocument().addDocumentListener(textModifyListener);

        protocolGroup = new ButtonGroup();
        protocolGroup.add(HTTPRadioButton);
        protocolGroup.add(HTTPSRadioButton);

        HTTPSRadioButton.addActionListener(ProtocolButtonListener);
        HTTPRadioButton.addActionListener(ProtocolButtonListener);

        this.portText.getDocument().addDocumentListener(textModifyListener);
        this.pathText.getDocument().addDocumentListener(textModifyListener);

        refresh();
    }

    private void setupUI(){
        setLayout(new GridLayoutManager(5, 2, new Insets(4, 4, 4, 4), -1, -1));
        final JLabel label1 = new JLabel();
        label1.setText(Messages.getString("AddServerControl.ServerPrompt"));
        //this.$$$loadLabelText$$$(label1, ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages").getString("AddServerControl.ServerPrompt"));
        add(label1, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        serverText = new JTextField();
        add(serverText, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
                GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1),
                null, 0, false));
        connectionDetails = new JPanel();

        connectionDetails.addPropertyChangeListener("enabled", new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (!evt.getPropertyName().equals("enabled"))
                    return;
                UIHelpers.enableComponents(connectionDetails, (boolean)evt.getNewValue());
            }
        });

        connectionDetails.setLayout(new GridLayoutManager(3, 4, new Insets(0, 0, 0, 0), -1, -1));
        add(connectionDetails, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        connectionDetails.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black),
                Messages.getString("AddServerControl.ConnectionDetailsGroupText")));
        final JLabel label2 = new JLabel();
        label2.setText(Messages.getString("AddServerControl.PathPrompt"));
        //this.$$$loadLabelText$$$(label2, ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages").getString("AddServerControl.PathPrompt"));
        connectionDetails.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label3 = new JLabel();
        label3.setText(Messages.getString("AddServerControl.PortPrompt"));
        //this.$$$loadLabelText$$$(label3, ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages").getString("AddServerControl.PortPrompt"));
        connectionDetails.add(label3, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label4 = new JLabel();
        label4.setText(Messages.getString("AddServerControl.ProtocolPrompt"));
        //this.$$$loadLabelText$$$(label4, ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages").getString("AddServerControl.ProtocolPrompt"));
        connectionDetails.add(label4, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        pathText = new JTextField();
        pathText.setText(DEFAULT_PATH);
        //pathText.setText(ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages").getString("AddServerControl.PathPromptDefault"));
        connectionDetails.add(pathText, new GridConstraints(0, 1, 1, 3, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));

        MaskFormatter formatter = null;
        try {
            formatter = new MaskFormatter("#####");
        } catch (ParseException e) {
            Messages.showErrorDialog(e.getLocalizedMessage(), "Error Occurred");
        }
        if (formatter != null)
            portText = new JFormattedTextField(formatter);
        else
            portText = new JFormattedTextField();

        portText.setText("8080");
        connectionDetails.add(portText, new GridConstraints(1, 1, 1, 3, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
                new Dimension(150, -1), null, 0, false));
        HTTPRadioButton = new JRadioButton();
        HTTPRadioButton.setText(Messages.getString("AddServerControl.ProtocolHTTPButton"));
        //HTTPRadioButton.setLabel(Messages.getString("AddServerControl.ProtocolHTTPButton"));
        //HTTPRadioButton.setLabel(ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages")
        // .getString("AddServerControl.ProtocolHTTPButton"));
        HTTPRadioButton.setSelected(true);
        HTTPRadioButton.setText(Messages.getString("AddServerControl.ProtocolHTTPButton"));
        connectionDetails.add(HTTPRadioButton, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        HTTPSRadioButton = new JRadioButton();
        HTTPSRadioButton.setText(Messages.getString("AddServerControl.ProtocolHTTPSButton"));
        //HTTPSRadioButton.setLabel(Messages.getString("AddServerControl.ProtocolHTTPSButton"));
        //HTTPSRadioButton.setLabel(ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages")
        // .getString("AddServerControl.ProtocolHTTPSButton"));
        HTTPSRadioButton.setText(Messages.getString("AddServerControl.ProtocolHTTPSButton"));
        connectionDetails.add(HTTPSRadioButton, new GridConstraints(2, 2, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        connectionDetails.add(spacer1, new GridConstraints(2, 3, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JLabel label5 = new JLabel();
        label5.setText(Messages.getString("AddServerControl.PreviewPrompt"));
        //this.$$$loadLabelText$$$(label5, ResourceBundle.getBundle("com/MichaelBulava/tfs/vcsintegration/core/Messages")
        // .getString("AddServerControl.PreviewPrompt"));
        add(label5, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        add(spacer2, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1,
                GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        previewText = new JTextField();
        previewText.setEnabled(false);
        add(previewText, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
                GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1),
                null, 0, false));
    }

    private void protocolButtonSelected(){
        if (this.HTTPRadioButton.isSelected() && DEFAULT_PORT_HTTPS.equals(this.portText.getText())){
            portText.setText(DEFAULT_PORT_HTTP);
        } else if (this.HTTPSRadioButton.isSelected() && DEFAULT_PORT_HTTP.equals(this.portText.getText().trim())){
            portText.setText(WELL_KNOWN_PORT_HTTPS);
        } else {
            refresh();
        }
    }

    private void refresh(){
        if (!this.validator.getValidity().isValid()){
            //TODO enable?
            this.serverURI = null;
            this.previewText.setText(this.validator.getValidity().getFirstMessage().getMessage());
            return;
        }
        String serverName = this.serverText.getText().trim();
        if ((serverName.contains(":")) && (!serverName.startsWith("[")))
        {
            try
            {
                this.serverURI = ServerURIUtils.normalizeURI(URIUtils.newURI(serverName), true);
                if (this.serverURI.getHost() != null)
                {
                    //SWTUtil.setCompositeEnabled(this.connectionDetailsGroup, false);
                    connectionDetails.setEnabled(false);
                    this.previewText.setText(this.serverURI.toString());

                    return;
                }
            }
            catch (IllegalArgumentException e)
            {
                this.serverURI = null;
            }
            this.serverURI = null;
            this.previewText.setText(Messages.getString("AddServerControl.ErrorServerNameEmpty"));

            return;
        }
        String enteredPath = this.pathText.getText().trim();
        String path = "/" + enteredPath;
        String port = this.portText.getText().trim();
        boolean https = this.HTTPSRadioButton.isSelected();
        String scheme = https ? "https" : "http";

        String[] serverNameAndPath = serverName.split(Pattern.quote("/"), 2);
        if (serverNameAndPath.length > 0){
            String uriServerName = serverNameAndPath[0];
            String uriPath = serverNameAndPath.length > 1 ? "/" + serverNameAndPath[1] : null;
            boolean isHosted = false;
            for (int i = 0; i < HOSTED_SERVICE_DOMAIN_SUFFIXES.length; i++) {
                if ((LocaleInvariantStringHelpers.caseInsensitiveEndsWith(uriServerName, HOSTED_SERVICE_DOMAIN_SUFFIXES[i]))
                        || (LocaleInvariantStringHelpers.caseInsensitiveEndsWith(uriServerName, HOSTED_SERVICE_DOMAIN_SUFFIXES[i] + "."))){
                    isHosted = true;
                    break;
                }
            }
            if (isHosted){
                //SWTUtil.setCompositeEnabled(this.connectionDetailsGroup, false);
                connectionDetails.setEnabled(false);
                try{
                    this.serverURI = ServerURIUtils.normalizeURI(URIUtils.newURI(HOSTED_SERVICE_DEFAULT_SCHEME,
                            uriServerName, uriPath, null, null), true);
                } catch (IllegalArgumentException e) {
                    this.serverURI = null;
                    this.previewText.setText(Messages.getString("AddServerControl.ErrorServerNameEmpty"));
                    return;
                }
                this.previewText.setText(this.serverURI.toString());

                return;
            }
        }
        //SWTUtil.setCompositeEnabled(this.connectionDetailsGroup, true);
        connectionDetails.setEnabled(true);
        if (serverName.length() == 0){
            this.serverURI = null;
            this.previewText.setText(Messages.getString("AddServerControl.ErrorServerNameEmpty"));

            return;
        }
        if (port.length() == 0) {
            this.serverURI = null;
            this.previewText.setText(Messages.getString("AddServerControl.ErrorPortEmpty"));

            return;
        }
        try {
            Integer.parseInt(port);
        } catch (NumberFormatException e) {
            this.serverURI = null;
            this.previewText.setText(Messages.getString("AddServerControl.ErrorPortEmpty")); return;
        }
        String authority;
        if ((!https && WELL_KNOWN_PORT_HTTP.equals(port)) || (https && WELL_KNOWN_PORT_HTTPS.equals(port))) {
            authority = serverName;
        } else {
            authority = MessageFormat.format("{0}:{1}", new Object[]{serverName, port});
        }
        try {
            this.serverURI = ServerURIUtils.normalizeURI(URIUtils.newURI(scheme, authority, path, null, null), true);
        } catch (IllegalArgumentException e) {
            this.serverURI = null;
            this.previewText.setText(Messages.getString("AddServerControl.ErrorServerNameEmpty"));

            return;
        }
        this.previewText.setText(this.serverURI.toString());
    }

    public URI getServerURI(){
        return this.serverURI;
    }

    public Validator getValidator(){
        return this.validator;
    }

}
